import os
import subprocess
import re
import argparse
import json
import tempfile
from datetime import datetime, timedelta

def parse_time(time_str):
    """将时间字符串转换为秒数"""
    try:
        if '.' in time_str:
            time_obj = datetime.strptime(time_str, "%H:%M:%S.%f")
        else:
            time_obj = datetime.strptime(time_str, "%H:%M:%S")
        return time_obj.hour * 3600 + time_obj.minute * 60 + time_obj.second + time_obj.microsecond / 1000000
    except ValueError:
        try:
            return float(time_str)
        except:
            return 0

def format_time(seconds):
    """将秒数格式化为 HH:MM:SS.ms """
    td = timedelta(seconds=seconds)
    hours, remainder = divmod(td.seconds, 3600)
    minutes, seconds = divmod(remainder, 60)
    milliseconds = td.microseconds // 1000
    return f"{hours:02d}:{minutes:02d}:{seconds:02d}.{milliseconds:03d}"

def get_video_duration(input_file):
    """获取视频总时长（秒）"""
    try:
        cmd = [
            'ffprobe',
            '-v', 'error',
            '-show_entries', 'format=duration',
            '-of', 'json',
            input_file
        ]
        
        result = subprocess.run(cmd, stdout= subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        data = json.loads(result.stdout)
        return float(data['format']['duration'])
    except Exception:
        return 0

def detect_frozen_frames(input_file, min_duration=1.0, noise_threshold=0.001):
    """
    检测视频中的静止画面区间
    
    参数:
    input_file: 输入视频文件路径
    min_duration: 最小静止持续时间 (秒)
    noise_threshold: 噪声容差阈值 (0-1)
    
    返回:
    静止画面区间列表 [(start1, end1), (start2, end2), ...]
    """
    try:
        # 构建FFmpeg命令
        cmd = [
            'ffmpeg',
            '-i', input_file,
            '-vf', f'freezedetect=n={noise_threshold}:d={min_duration}',
            '-map', '0:v:0',  # 只处理视频流
            '-f', 'null',
            '-'
        ]
        
        # 运行命令并捕获输出（使用二进制模式）
        result = subprocess.run(
            cmd,
            stderr=subprocess.PIPE,
            stdout=subprocess.PIPE,
            check=True
        )
        
        # 尝试多种编码方式解析输出
        output = None
        encodings = ['utf-8', 'gbk', 'latin-1', 'cp1252']
        
        for encoding in encodings:
            try:
                output = result.stderr.decode(encoding)
                break
            except UnicodeDecodeError:
                continue
        
        if output is None:
            # 如果所有编码都失败，使用错误忽略模式
            output = result.stderr.decode('utf-8', errors='ignore')
        
        frozen_intervals = []
        
        # 正则表达式匹配冻结帧区间
        start_pattern = r"freeze_start: (\d+\.?\d*)"
        end_pattern = r"freeze_end: (\d+\.?\d*)"
        duration_pattern = r"freeze_duration: (\d+\.?\d*)"
        
        starts = []
        for match in re.findall(start_pattern, output):
            try:
                starts.append(float(match))
            except:
                continue
        
        ends = []
        for match in re.findall(end_pattern, output):
            try:
                ends.append(float(match))
            except:
                continue
        
        durations = []
        for match in re.findall(duration_pattern, output):
            try:
                durations.append(float(match))
            except:
                continue
        
        # 确保时间点配对
        if len(starts) == len(ends):
            frozen_intervals = list(zip(starts, ends))
        elif len(starts) > len(ends):
            # 处理最后一个区间可能没有结束时间的情况
            for i in range(len(ends)):
                frozen_intervals.append((starts[i], ends[i]))
            # 如果最后一个冻结区间没有结束时间，使用视频时长
            duration = get_video_duration(input_file)
            if starts[-1] < duration:
                frozen_intervals.append((starts[-1], duration))
        
        # 修复重叠区间问题
        if frozen_intervals:
            # 按开始时间排序
            frozen_intervals.sort(key=lambda x: x[0])
            
            # 合并重叠区间
            merged = []
            current_start, current_end = frozen_intervals[0]
            
            for start, end in frozen_intervals[1:]:
                if start <= current_end:  # 有重叠
                    current_end = max(current_end, end)  # 合并区间
                else:
                    merged.append((current_start, current_end))
                    current_start, current_end = start, end
            
            merged.append((current_start, current_end))
            frozen_intervals = merged
        
        return frozen_intervals, durations
        
    except subprocess.CalledProcessError as e:
        print(f"FFmpeg错误: {e.stderr.decode('utf-8', errors='ignore')}")
        return [], []
    except Exception as e:
        print(f"检测静止画面时出错: {str(e)}")
        return [], []
    
def main():
    parser = argparse.ArgumentParser(description='检测视频中的静止画面区间')
    parser.add_argument('input', help='输入视频文件路径')
    parser.add_argument('-d', '--min-duration', type=float, default=1.0,
                        help='最小静止持续时间 (秒, 默认1.0)')
    parser.add_argument('-n', '--noise-threshold', type=float, default=0.01,
                        help='噪声容差阈值 (0-1, 默认0.01)')
    parser.add_argument('-o', '--output', default="detect_frozen_frames_output.txt", help='输出结果文件 (可选)')
    
    args = parser.parse_args()
    
    if not os.path.isfile(args.input):
        print(f"错误: 输入文件不存在 - {args.input}")
        return
    
    # 删除上一次的输出文件
    if args.output and os.path.isfile(args.output):
        os.remove(args.output)
    
    print(f"分析视频: {args.input}")
    print(f"最小静止持续时间: {args.min_duration} 秒")
    print(f"噪声容差阈值: {args.noise_threshold}")
    
    # 检测静止画面区间
    frozen_intervals, durations = detect_frozen_frames(
        args.input,
        min_duration=args.min_duration,
        noise_threshold=args.noise_threshold
    )
    
    # 获取视频总时长
    total_duration = get_video_duration(args.input)
    
    if frozen_intervals:
        print("\n检测到的静止画面区间:")
        print("=" * 75)
        print(f"{'开始时间':<15} {'结束时间':<15} {'持续时间':<15} {'位置(%)':<10} {'帧变化量':<10}")
        print("-" * 75)
        
        output_lines = []
        total_frozen = 0
        last_end = 0
        
        for i, (start, end) in enumerate(frozen_intervals):
            # 修复区间顺序问题
            if start < last_end:
                start = last_end
            if start >= end:
                continue
                
            duration = end - start
            position = (start / total_duration * 100) if total_duration > 0 else 0
            frame_change = durations[i] if i < len(durations) else duration
            
            # 确保位置百分比合理
            if position > 100:
                position = 100
                
            # 确保帧变化量合理
            if frame_change <= 0:
                frame_change = duration
                
            # 格式化输出
            start_str = format_time(start)
            end_str = format_time(end)
            duration_str = f"{duration:.3f}秒"
            position_str = f"{position:.1f}%"
            frame_change_str = f"{frame_change:.4f}"
            
            print(f"{start_str:<15} {end_str:<15} {duration_str:<15} {position_str:<10} {frame_change_str:<10}")
            output_lines.append(f"{start_str}\t{end_str}\t{duration_str}\t{position_str}\t{frame_change_str}")
            
            total_frozen += duration
            last_end = end
        
        print("=" * 75)
        frozen_percent = (total_frozen / total_duration * 100) if total_duration > 0 else 0
        print(f"总静止画面时间: {total_frozen:.3f}秒 ({frozen_percent:.2f}%)")
        
        # 输出到文件
        if args.output:
            # 保存结果到文件 utf-8 编码
            with open(args.output, 'w', encoding='utf-8') as f:
                f.write("开始时间\t结束时间\t持续时间\t位置(%)\t帧变化量\n")
                f.write("\n".join(output_lines))
                f.write(f"\n\n总静止画面时间: {total_frozen:.3f}秒 ({frozen_percent:.2f}%)")
            print(f"\n结果已保存到: {args.output}")
    else:
        print("\n未检测到静止画面区间")

if __name__ == "__main__":
    main()